package com.jdk.demo.primitive;

import java.nio.charset.Charset;

public class StringDemo {
	
	public static void main(String[] args) {
		test();
		test2();
		test3();
		String s = new String("测试数据");
		s.getBytes(Charset.forName("utf-8"));
	}
	
	/**
	 * 1.常量与常量池
	在这里需要引入常量池这个简单的概念。
	常量池(constant pool)指的是在编译期被确定，并被保存在已编译的.class文件中的一些数据。
	它包括了关于类、方法、接口等中的常量，也包括字符串常量。
	
	看例1：
	首先，我们要知结果Java会确保一个字符串常量只有一个拷贝。
	因为例子中的a0和a1都是字符串常量，它们在编译期就被确定了，所以a0==a1为true；
	而”learning ”和”String”也都是字符串常量，当一个字符串由多个字符串常量连接而成时
	，它自己肯定也是字符串常量，所以a2也同样在编译期就被解析为一个字符串常量，
	所以as2也是常量池中”learning String”的一个引用。所以我们得出a0==a1==a2;
	到这里我们就可以理解string通过这种常量池中相同常量共享对象的方式实现了类似于缓存的享元模式设计
	 */
	private static void test(){
		String a0 = "learning java";
		String a1 = "learning java";
		String a2 = "learning" + " java";
		System.out.println(a0 == a1);
		System.out.println(a1 == a2);
	}
	
	/**
	 * String的构造方法
	用new String() 创建的字符串不是常量，不能在编译期就确定，所以new String() 创建的字符串不放入常量池中，它们有自己的地址空间。
	
	a0还是常量池中”learning String”的应用，a1因为无法在编译期确定，所以是运行时创建的新对象”learning String”
	的引用，a2因为有后半部分new String(“String”)所以也无法在编译期确定，所以也是一个新创建对象”learning String”
	的应用;明白了这些也就知道为何得出此结果了。
	 */
	private static void test2(){
		String a0 = "learning java";
		String a1 = new String("learning java");
		String a2 = "learning" + new String(" java");
		System.out.println(a0 == a1);
		System.out.println(a1 == a2);
	}
	
	/**
	 * String.intern()扩充常量池：
	存在于.class文件中的常量池，在运行期被JVM装载，并且可以扩充。String的intern()方法就是扩充常量池的一个方法；
	当一个String实例str调用intern()方法时，Java查找常量池中是否有相同Unicode的字符串常量，如果有，
	则返回其的引用，如果没有，则在常量池中增加一个Unicode等于str的字符串并返回它的引用；
	 */
	private static void test3(){
		String a0 = "learning java";
		String a1 = new String("learning java");
		a1 = a1.intern();
		System.out.println(a0 == a1);
		String a3 = new String("learning java2");
		String a4 = new String("learning java2");
		System.out.println(a3.intern() == a4.intern());
	}

}
